#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio_ex.h"
#include "iot_gpio.h"
#include "iot_uart.h"
#include "iot_errno.h"
#include "iot_main.h"
#include "iot_profile.h"
#include "iot_log.h"
#include "oled_ssd1306.h"
#include "oled_fonts.h"
#include <hi_gpio.h>
#include <hi_io.h>
#include <hi_uart.h>
#include "MQTTClient.h"

#define SENSOR_GPIO 11
#define SENSOR_TASK_STACK_SIZE 4096
#define SENSOR_TASK_PRIO 25
#define ST_OUT_LOW IoTGpioSetOutputVal(SENSOR_GPIO, 0)
#define ST_OUT_HIGH IoTGpioSetOutputVal(SENSOR_GPIO, 1)
#define LED_TEST_GPIO 9
#define LED_INTERVAL_TIME_US 300000
#define KEY1_GPIO 7
#define KEY2_GPIO 5
#define STATUS_INTERVAL_TIME_US 3000000 

typedef enum{
	HOT=0,
	COMFORTABLE,
	COLD,
} EnvironmentStatus;

uint8_t temperature;
uint8_t humidity;
int ledStatus = -1;
uint8_t status=COMFORTABLE;

static long long tick = 0;

void IO_OUT(void)
{
	IoTGpioSetDir(SENSOR_GPIO, IOT_GPIO_DIR_OUT);
}

void IO_IN(void)
{
	IoTGpioSetDir(SENSOR_GPIO, IOT_GPIO_DIR_IN);
	IoSetPull(SENSOR_GPIO, IOT_IO_PULL_NONE);
}

void DHT11_Rst(void)
{
	IO_OUT();
	ST_OUT_LOW;
	hi_udelay(20000);
	ST_OUT_HIGH;
	hi_udelay(35);
}

unsigned char GpioGetInput(unsigned int id, IotGpioValue *val)
{
	IoTGpioGetInputVal(id, val);
	return *val;
}

unsigned char DHT11_Check(void)
{
	unsigned char cnt = 0;
	IotGpioValue gpio_val = IOT_GPIO_VALUE1;
	IO_IN();
	while (GpioGetInput(SENSOR_GPIO, &gpio_val) && cnt < 100)
	{
		cnt++;
		hi_udelay(1);
	};
	if (cnt >= 100)
	{
		IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
		return 1;
	}
	else
		cnt = 0;
	while ((!GpioGetInput(SENSOR_GPIO, &gpio_val)) && cnt < 100)
	{
		cnt++;
		hi_udelay(1);
	};
	if (cnt >= 100)
	{
		return 1;
	}
	return 0;
}

unsigned char DHT11_Init(void)
{
	DHT11_Rst();
	return DHT11_Check();
}

unsigned char DHT11_Read_Bit(void)
{
	unsigned char cnt = 0;
	IotGpioValue gpio_val = IOT_GPIO_VALUE1;
	while (GpioGetInput(SENSOR_GPIO, &gpio_val) && cnt < 100)
	{
		cnt++;
		hi_udelay(1);
	}
	cnt = 0;
	while (!GpioGetInput(SENSOR_GPIO, &gpio_val) && cnt < 100)
	{
		cnt++;
		hi_udelay(1);
	}
	hi_udelay(40);
	if (GpioGetInput(SENSOR_GPIO, &gpio_val))
		return 1;
	else
		return 0;
}

unsigned char DHT11_Read_Byte(void)
{
	unsigned char i, dat = 0;
	for (i = 0; i < 8; i++)
	{
		dat <<= 1;
		dat |= DHT11_Read_Bit();
	}
	return dat;
}

unsigned char DHT11_Read_Data(unsigned char *temp, unsigned char *humi)
{
	unsigned char buf[5];
	unsigned char i;
	DHT11_Rst();
	if (DHT11_Check() == 0)
	{
		for (i = 0; i < 5; i++)
		{
			buf[i] = DHT11_Read_Byte();
		}
		if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
		{
			*humi = buf[0];
			*temp = buf[2];
			printf("Data Got...");
		}
	}
	else
		return 1;
	return 0;
}

/* 小数转字符串
 * 输入：double 小数
 * 输出：转换后的字符串
 */
unsigned char *FloatToString(double d, unsigned char *str)
{
	unsigned char str1[40] = {0};
	double data = d;
	unsigned char *floatString = str;
	int j = 0;
	int m;

	if (str == NULL)
	{
		return;
	}

	m = (int)data; /* 浮点数的整数部分 */
	while (m > 0)
	{
		str1[j++] = m % 10 + '0'; /* 10 : 对10求余 */
		m = m / 10;				  /* 10 : 对10求模 */
	}

	for (int k = 0; k < j; k++)
	{
		floatString[k] = str1[j - 1 - k]; /* 1： 被提取的整数部分正序存放到另一个数组 */
	}
	floatString[j++] = '.';

	data = data - (int)data; /* 小数部分提取 */
	for (int i = 0; i < 1; i++)
	{					  /* 1: 取小数点1位 */
		data = data * 10; /* 10：取整数 */
		floatString[j++] = (int)data + '0';
		data = data - (int)d;
	}

	while (floatString[--j] == '0')
	{
		if (j == 0)
		{
			break;
		}
	}
	floatString[++j] = '\0';

	return floatString;
}

void LedSensorKeyGpioInit(void){

	IoTGpioInit(LED_TEST_GPIO);
	IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);

	IoTGpioInit(SENSOR_GPIO);
	IoSetFunc(SENSOR_GPIO, IOT_IO_FUNC_GPIO_11_GPIO);
	IoTGpioSetDir(SENSOR_GPIO, IOT_GPIO_DIR_OUT);

	IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
	IoTGpioSetOutputVal(SENSOR_GPIO, 1);

	IoTGpioInit(KEY1_GPIO);
	IoSetFunc(KEY1_GPIO, IOT_IO_FUNC_GPIO_7_GPIO);
	IoTGpioSetDir(KEY1_GPIO, IOT_GPIO_DIR_IN);
	IoSetPull(KEY1_GPIO, IOT_IO_PULL_UP);

	IoTGpioInit(KEY2_GPIO);
	IoSetFunc(KEY2_GPIO, IOT_IO_FUNC_GPIO_5_GPIO);
	IoTGpioSetDir(KEY2_GPIO, IOT_GPIO_DIR_IN);
	IoSetPull(KEY2_GPIO, IOT_IO_PULL_UP);
}

static void Key1InterruptCallback(const char *arg){
	(void)arg;
	usleep(5000);
	IotGpioValue gpio_val = IOT_GPIO_VALUE1;
	if(GpioGetInput(KEY1_GPIO, &gpio_val)==0){
		status = HOT;
	}
	return;
}

static void Key2InterruptCallback(const char *arg){
	(void)arg;
	usleep(5000);
	IotGpioValue gpio_val = IOT_GPIO_VALUE1;
	if(GpioGetInput(KEY2_GPIO, &gpio_val)==0){
		switch(status){
			case HOT:
				status = COMFORTABLE;
				break;
			case COMFORTABLE:
				status = COLD;
				break;
			case COLD:
				status = HOT;
				break;
		}
	}
	return;
}

void uart_enable(void)
{
	unsigned int ret = 0;
	IoTGpioInit(IOT_IO_NAME_GPIO_0);
	IoTGpioInit(IOT_IO_NAME_GPIO_1);
	IoSetFunc(IOT_IO_NAME_GPIO_0, IOT_IO_FUNC_GPIO_0_UART1_TXD);
	IoSetFunc(IOT_IO_NAME_GPIO_1, IOT_IO_FUNC_GPIO_1_UART1_RXD);
	IotUartAttribute uart_attr;
	uart_attr.baudRate = 9600;
	uart_attr.dataBits = 8;
	uart_attr.stopBits = 1;
	uart_attr.parity = 0;
	ret = IoTUartInit(1, &uart_attr);
	if (ret != IOT_SUCCESS)
	{
		printf("Failed to init uart\r\n");
		return;
	}
	printf("UART init Success\r\n");
}

void KeyRegisterIsr(void){
	uint8_t ret = IOT_SUCCESS;
	// ret = IoTGpioRegisterIsrFunc(KEY1_GPIO, IOT_INT_TYPE_EDGE,
    // IOT_GPIO_EDGE_FALL_LEVEL_LOW, Key1InterruptCallback, NULL); /* 5 */
    // if (ret == IOT_SUCCESS) {
    //     printf("Key1 Registered\r\n");
    // }
	ret = IoTGpioRegisterIsrFunc(KEY2_GPIO, IOT_INT_TYPE_EDGE,
    IOT_GPIO_EDGE_FALL_LEVEL_LOW, Key2InterruptCallback, NULL); /* 5 */
    if (ret == IOT_SUCCESS) {
        printf("Key2 Registered\r\n");
    }
	return;
}

void LedBlink(void){
	IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
	usleep(LED_INTERVAL_TIME_US);
	IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
	usleep(LED_INTERVAL_TIME_US);
}

void StatusDetect(void){
	if(temperature>30){
		status = HOT;
	}
	else if(temperature>10){
		status = COMFORTABLE;
	}
	else{
		status = COLD;
	}
}

void StatusDisplay(void){
	uint8_t str[16];
	switch(status){
		case COMFORTABLE:
			sprintf(str,"T:%d(C)",temperature);
			OledShowString(6, 1, str, 2);
			sprintf(str,"H:%d(%%RH)",humidity);
			OledShowString(6, 4, str, 2);
			OledShowImg(79, 1, gImage_comfortable, 48*48);
			usleep(STATUS_INTERVAL_TIME_US);
			break;
		case HOT:
			sprintf(str,"T:%d(C)",39);
			OledShowString(6, 1, str, 2);
			sprintf(str,"H:%d(%%RH)",26);
			OledShowString(6, 4, str, 2);
			OledShowImg(79, 1, gImage_hot, 48*48);
			usleep(STATUS_INTERVAL_TIME_US);
			break;
		case COLD:
			//OledFillScreen(0);
			sprintf(str,"T:%d(C)",9);
			OledShowString(6, 1, str, 2);
			sprintf(str,"H:%d(%%RH)",13);
			OledShowString(6, 4, str, 2);
			OledShowImg(79, 1, gImage_cold, 48*48);
			usleep(STATUS_INTERVAL_TIME_US);
			break;
	}
}

static void LedCmdCallBack(int qos, const char *topic, const char *payload)
{
    IOT_LOG_DEBUG("RCVMSG:QOS:%d TOPIC:%s PAYLOAD:%s\r\n", qos, topic, payload);
    /* 云端下发命令后，板端的操作处理 */
    if (strstr(payload, "light") != NULL) {
        if (strstr(payload, "0") != NULL) {
			IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
            ledStatus = HI_FALSE;
        } else {
            IoTGpioSetOutputVal(LED_TEST_GPIO, 0);
            ledStatus = HI_TRUE;
        }
    }
    return HI_NULL;
}

hi_void IoTPublish(void)
{
    /* reported attribute */
    WeChatProfile weChatProfile = {
        .subscribeType = "type",
        .status.subState = "state",
        .status.subReport = "reported",
        .status.reportVersion = "version",
        .status.Token = "clientToken",
        /* report temperature */
        .reportAction.subDeviceActionTemperature = "temperature",
        .reportAction.temperatureData = temperature, /* 26 :temperature data */
        /* report humidity */
        .reportAction.subDeviceActionHumidity = "humidity",
        .reportAction.humidityActionData = humidity, /* humidity data */
    };

    /* report light */
    if (ledStatus == HI_TRUE) {
        weChatProfile.reportAction.subDeviceActionLight = "light";
        weChatProfile.reportAction.lightActionStatus = 1; /* 1: light on */
    } else if (ledStatus == HI_FALSE) {
        weChatProfile.reportAction.subDeviceActionLight = "light";
        weChatProfile.reportAction.lightActionStatus = 0; /* 0: light off */
    } else {
        weChatProfile.reportAction.subDeviceActionLight = "light";
        weChatProfile.reportAction.lightActionStatus = 0; /* 0: light off */
    }
    /* profile report */
    IoTProfilePropertyReport(CONFIG_USER_ID, &weChatProfile);
}


static void *SensorTask(const char *arg)
{
	(void)arg;
	IotGpioValue gpio_val = IOT_GPIO_VALUE1;
	LedSensorKeyGpioInit();
	uart_enable();
	KeyRegisterIsr();

	while(OledInit()!=IOT_SUCCESS){
		printf("Oled Init Failed, Retrying...\r\n");
	}
	OledFillScreen(0);

	while (DHT11_Init()){
		printf("DHT11 UnReady, Waiting...\r\n");
		usleep(500000);
	}
	printf("DHT11 OK\r\n");

	WifiStaReadyWait();
	cJsonInit();
	IoTSetMsgCallback(LedCmdCallBack);	//创建命令处理函数
	IoTMain();
	printf("IoTMain Ends...\r\n");
	while (1)
	{
		DHT11_Read_Data(&temperature, &humidity);
		if(GpioGetInput(LED_TEST_GPIO, &gpio_val)){
			ledStatus = 0;
		}
		else{
			ledStatus = 1;
		}
		IoTPublish();
		printf("IoTPublish Ends...\r\n");
		printf("Temperature: %d, Humidity: %d", temperature, humidity);
		StatusDetect();
		StatusDisplay();
		LedBlink();
	}
	return NULL;
}

static void SensorTaskEntry(void)
{
	osThreadAttr_t attr;
	IoTWatchDogDisable();
	attr.name = "SensorTask";
	attr.attr_bits = 0U;
	attr.cb_mem = NULL;
	attr.cb_size = 0U;
	attr.stack_mem = NULL;
	attr.stack_size = SENSOR_TASK_STACK_SIZE;
	attr.priority = SENSOR_TASK_PRIO;

	if (osThreadNew((osThreadFunc_t)SensorTask, NULL, &attr) == NULL)
	{
		printf("Falied to create SensorTask!\n");
	}
}

SYS_RUN(SensorTaskEntry);
